import json
import re
from pathlib import Path
from typing import Dict, Any, Optional, List, Union
from src.base.registry import bera

class ConfigGenerator:
    """配置生成器，用于从SQL解析结果生成配置文件"""

    def __init__(self):
        """初始化配置生成器"""
        self.version = "1.0"
        # 注册配置生成器
        self._generators = {
            "common": self._generate_common_config,
            "java": self._generate_java_config
        }
        # 枚举值提取的正则表达式
        self.dict_pattern = re.compile(r'(\d+)-([^，,]+)[，,]?')

        # 类型映射
        self.type_mapping = {
            # 整数类型
            'tinyint': self._map_tinyint,
            'smallint': lambda x: 'numeric',
            'mediumint': lambda x: 'numeric',
            'int': lambda x: 'numeric',
            'bigint': lambda x: 'numeric',

            # 浮点类型
            'float': lambda x: 'decimal',
            'double': lambda x: 'decimal',
            'decimal': lambda x: 'decimal',

            # 字符串类型
            'char': lambda x: 'literal',
            'varchar': lambda x: 'literal',
            'tinytext': lambda x: 'text',
            'text': lambda x: 'text',
            'mediumtext': lambda x: 'text',
            'longtext': lambda x: 'text',
            'enum': lambda x: 'enum',
            'set': lambda x: 'enum',

            # 日期时间类型
            'date': lambda x: 'date',
            'time': lambda x: 'time',
            'datetime': lambda x: 'datetime',
            'timestamp': lambda x: 'datetime',
            'year': lambda x: 'year',

            # 二进制类型
            'binary': lambda x: 'binary',
            'varbinary': lambda x: 'binary',
            'tinyblob': lambda x: 'binary',
            'blob': lambda x: 'binary',
            'mediumblob': lambda x: 'binary',
            'longblob': lambda x: 'binary',

            # JSON类型
            'json': lambda x: 'json'
        }

    def generate_from_file(self, table_name: str, test_mode: bool = False, base_path: Optional[Path] = None) -> Dict[str, Any]:
        """从文件生成配置

        Args:
            table_name: 表名
            test_mode: 是否为测试模式
            base_path: 基础路径

        Returns:
            Dict[str, Any]: 生成的配置
        """
        # 构建文件路径
        base_dir = base_path if base_path else Path(".")
        if test_mode:
            sql_json_path = base_dir / "artifacts/test/tables" / table_name / "config" / "sql.json"
            mark_json_path = base_dir / "artifacts/test/tables" / table_name / "mark.auto.json"
            output_dir = base_dir / "artifacts/test/tables" / table_name / "config"
        else:
            sql_json_path = base_dir / "artifacts/miaoma/tables" / table_name / "config" / "sql.json"
            mark_json_path = base_dir / "artifacts/miaoma/tables" / table_name / "mark.auto.json"
            output_dir = base_dir / "artifacts/miaoma/tables" / table_name / "config"

        # 检查 sql.json 是否存在
        if not sql_json_path.exists():
            raise FileNotFoundError(f"SQL描述文件不存在: {sql_json_path}")

        # 读取 sql.json
        with open(sql_json_path, "r") as f:
            sql_auto = json.load(f)

        # 读取 mark.json 中的配置格式
        config_formats = ["common"]
        if mark_json_path.exists():
            with open(mark_json_path, "r") as f:
                mark_data = json.load(f)
                if "config_formats" in mark_data:
                    config_formats = mark_data["config_formats"]

        # 生成配置
        output_dir.mkdir(parents=True, exist_ok=True)
        configs = {}
        for fmt in config_formats:
            config = self._generate_config(sql_auto, fmt)
            output_file = output_dir / f"{fmt}.json"
            with open(output_file, "w") as f:
                json.dump(config, f, indent=2, ensure_ascii=False)
            configs[fmt] = config

        return configs

    def generate(self, sql_data: Dict[str, Any]) -> Dict[str, Any]:
        """生成配置文件内容"""
        config = {
            "table": self._generate_table_config(sql_data),
            "columns": self._generate_columns_config(sql_data)
        }
        return config

    def _generate_table_config(self, sql_data: Dict[str, Any]) -> Dict[str, Any]:
        """生成表级配置"""
        table_info = sql_data.get("table", {})
        table_name = table_info.get("name", "")
        table_comment = table_info.get("comment", "")
        business_name = table_info.get("business_name", "")

        return {
            "description": table_comment or "未知表",
            "label": business_name.capitalize(),
            "api_prefix": f"/api/v1/{business_name}",
            "features": {
                "has_created_at": "created_at" in sql_data.get("columns", {}),
                "has_updated_at": "updated_at" in sql_data.get("columns", {}),
                "has_deleted_at": "deleted_at" in sql_data.get("columns", {}),
                "is_tenant": False,
                "is_org": False,
                "has_version": False,
                "has_workflow": False,
                "has_audit": False,
                "cache_enabled": False
            },
            "permissions": {
                "create": f"system:{business_name}:create",
                "read": f"system:{business_name}:read",
                "update": f"system:{business_name}:update",
                "delete": f"system:{business_name}:delete",
                "export": f"system:{business_name}:export",
                "import": f"system:{business_name}:import"
            }
        }

    def _generate_columns_config(self, sql_auto: Dict[str, Any]) -> List[Dict[str, Any]]:
        """生成列配置

        Args:
            sql_auto: SQL解析结果

        Returns:
            List[Dict[str, Any]]: 列配置列表
        """
        columns = []
        for column in sql_auto.get("columns", []):
            name = column["name"]
            data_type = self._map_data_type(column["type"])
            fmt = self._get_format(column["type"])

            # 生成 label
            if name == "id":
                label = "Id"
            else:
                # 将下划线替换为空格,并将每个单词首字母大写
                label = " ".join(word.capitalize() for word in name.split("_"))

            config = {
                "name": name,
                "label": label,
                "description": column.get("comment", ""),
                "data_type": data_type,
                "length": column.get("length", 0),
                "precision": column.get("precision", 0),
                "scale": column.get("scale", 0),
                "unsigned": column.get("unsigned", False),
                "required": not column.get("nullable", True),
                "auto_increment": column.get("auto_increment", False),
                "features": {
                    "searchable": True,
                    "sortable": True,
                    "filterable": True,
                    "exportable": True,
                    "importable": name not in ["id", "created_at", "updated_at"],
                    "editable": name not in ["id", "created_at", "updated_at"],
                    "addable": name not in ["id", "created_at", "updated_at"],
                    "viewable": True,
                    "selectable": True
                }
            }

            # 添加格式化配置
            if fmt:
                config["format"] = fmt

            columns.append(config)

        return columns

    def _generate_column_config(self, col_name: str, col_info: Dict[str, Any]) -> Dict[str, Any]:
        """生成单个字段的配置"""
        bera.logger.info(f"\nGenerating config for column: {col_name}")
        bera.logger.info(f"Column info: {col_info}")

        type_info = col_info.get("type", {})
        data_type = type_info.get("name", "").lower()
        length = type_info.get("length", 0)
        if isinstance(length, str):
            length = int(length) if length.isdigit() else 0

        comment = col_info.get("comment", "")
        nullable = col_info.get("nullable", True)
        default = col_info.get("default_value", None)

        bera.logger.info(f"Extracted info - data_type: {data_type}, length: {length}, comment: {comment}")

        # 确定字段类型
        field_type = self._determine_field_type(data_type, length, comment)
        bera.logger.info(f"Determined field type: {field_type}")

        # 基础配置
        config = {
            "label": self._generate_label(col_name),
            "description": self._generate_description(col_name, comment),
            "is_enum": field_type == "enum",
            "required": not nullable,
            "data_type": field_type,
            "searchable": col_name not in ["id", "created_at", "updated_at", "deleted_at"],
            "sortable": True,
            "filterable": col_name not in ["id"],
            "exportable": col_name not in ["id"],
            "importable": col_name not in ["id", "created_at", "updated_at", "deleted_at"]
        }

        # 添加类型特定的配置
        type_config = self._get_type_config(field_type, col_name, col_info)
        config.update(type_config)

        bera.logger.info(f"Generated config: {config}")
        return config

    def _determine_field_type(self, data_type: str, length: int, comment: str) -> str:
        """确定字段类型"""
        if data_type not in self.type_mapping:
            return "literal"

        if callable(self.type_mapping[data_type]):
            return self.type_mapping[data_type]({"length": length, "comment": comment})

        return self.type_mapping[data_type]

    def _map_tinyint(self, info: Dict[str, Any]) -> str:
        """映射 TINYINT 类型"""
        length = info.get("length", 4)
        comment = info.get("comment", "")

        # 如果 length 是 None，使用默认值 4
        if length is None:
            length = 4

        # TINYINT(1) 映射为 boolean
        if length == 1:
            return "boolean"

        # 检查是否有枚举选项
        if "：" in comment:
            return "enum"

        # 长度小于等于4，默认为枚举类型
        if length <= 4:
            return "enum"

        return "numeric"

    def _get_type_config(self, field_type: str, col_name: str, col_info: Dict[str, Any]) -> Dict[str, Any]:
        """获取类型特定的配置"""
        config = {}
        length = col_info.get("length", 0)
        if isinstance(length, str):
            length = int(length) if length.isdigit() else 0

        if field_type == "numeric":
            config.update({
                "min_value": 0 if col_name == "age" else 1,
                "max_value": 150 if col_name == "age" else 9999999999,
                "default_value": 0
            })

        elif field_type == "decimal":
            config.update({
                "precision": col_info.get("precision", 10),
                "scale": col_info.get("scale", 2),
                "min_value": None,
                "max_value": None,
                "default_value": 0.00
            })

        elif field_type == "literal":
            config.update({
                "min_length": 0,
                "max_length": length or 255,
                "pattern": None,
                "default_value": ""
            })

        elif field_type == "text":
            config.update({
                "rich_text": "富文本" in col_info.get("comment", ""),
                "support_markdown": False,
                "min_length": 0,
                "max_length": None,
                "default_value": None
            })

        elif field_type == "binary":
            config.update({
                "max_size": "5MB",
                "allowed_types": ["image/*", "application/pdf"],
                "storage_type": "local",
                "default_value": None
            })

        elif field_type == "datetime":
            config.update({
                "format": "YYYY-MM-DD HH:mm:ss",
                "timezone": True,
                "min_value": None,
                "max_value": None,
                "default_value": "CURRENT_TIMESTAMP" if col_info.get("default_value") == "CURRENT_TIMESTAMP" else None
            })

        elif field_type == "date":
            config.update({
                "format": "YYYY-MM-DD",
                "min_value": None,
                "max_value": None,
                "default_value": None
            })

        elif field_type == "time":
            config.update({
                "format": "HH:mm:ss",
                "with_timezone": False,
                "default_value": "00:00:00"
            })

        elif field_type == "year":
            config.update({
                "min_year": 1901,
                "max_year": 2155,
                "format": "YYYY",
                "default_value": None
            })

        elif field_type == "json":
            config.update({
                "schema": None,
                "validate_schema": False,
                "default_value": "{}"
            })

        elif field_type == "boolean":
            config.update({
                "true_value": 1,
                "false_value": 0,
                "true_label": "是",
                "false_label": "否",
                "default_value": False
            })

        elif field_type == "enum":
            # 从注释中提取枚举值
            comment = col_info.get("comment", "")
            enum_values = self._extract_enum_values(comment)
            if not enum_values:
                # 如果没有提取到枚举值，使用默认值
                enum_values = {"1": "选项1", "2": "选项2"}

            config.update({
                "enum_values": enum_values,
                "multiple": False,
                "default_value": list(enum_values.keys())[0] if enum_values else None
            })

        return config

    def _extract_enum_values(self, comment: str) -> Optional[Dict[str, str]]:
        """从注释中提取枚举值"""
        result = {}
        # 查找冒号后面的部分
        if "：" not in comment:
            return None

        enum_part = comment.split("：")[1]
        matches = self.dict_pattern.findall(enum_part)
        if not matches:
            return None

        for key, value in matches:
            result[key] = value
        return result

    def _has_enum_comment(self, comment: str) -> bool:
        """检查是否包含枚举值注释"""
        return bool(self.dict_pattern.search(comment))

    def _generate_label(self, field_name: str) -> str:
        """生成字段标签"""
        # 处理特殊字段
        if field_name == "id":
            return "ID"
        if field_name == "created_at":
            return "Createdat"
        if field_name == "updated_at":
            return "Updatedat"
        if field_name == "deleted_at":
            return "Deletedat"

        # 移除常见前缀
        name = field_name.replace("f_", "").replace("n_", "").replace("d_", "").replace("s_", "")
        # 移除 _id 后缀
        if name.endswith("_id"):
            name = name[:-3]
        # 首字母大写，保持其他字母不变
        return "".join(part.capitalize() for part in name.split("_"))

    def _generate_description(self, field_name: str, comment: str) -> str:
        """生成字段描述"""
        if not comment:
            return self._generate_label(field_name)

        # 移除枚举值说明
        desc = comment.split("：")[0] if "：" in comment else comment
        # 移除格式说明
        desc = desc.split("，")[0] if "，" in desc else desc
        return desc

    def _generate_common_config(self, sql_auto: Dict[str, Any]) -> Dict[str, Any]:
        """生成通用配置

        Args:
            sql_auto: SQL解析结果

        Returns:
            Dict[str, Any]: 通用配置

        Raises:
            ValueError: 当 business_name 不存在时抛出
        """
        table_info = sql_auto["table"]
        if "business_name" not in table_info:
            raise ValueError("business_name is required")
        business_name = table_info["business_name"]

        # 检查是否有 created_at 字段
        has_created_at = False
        has_updated_at = False
        for column in sql_auto.get("columns", []):
            if column["name"] == "created_at":
                has_created_at = True
            elif column["name"] == "updated_at":
                has_updated_at = True

        return {
            "version": self.version,
            "table": {
                "name": table_info["name"],
                "business_name": business_name,
                "description": table_info.get("comment", ""),
                "label": business_name.capitalize(),
                "api_prefix": f"/api/v1/{business_name}",
                "features": {
                    "searchable": True,
                    "sortable": True,
                    "filterable": True,
                    "exportable": True,
                    "importable": True,
                    "deletable": True,
                    "editable": True,
                    "addable": True,
                    "viewable": True,
                    "selectable": True,
                    "batch_deletable": True,
                    "batch_editable": True,
                    "tree": False,
                    "pagination": True,
                    "has_created_at": has_created_at,
                    "has_updated_at": has_updated_at
                },
                "permissions": {
                    "create": True,
                    "read": True,
                    "update": True,
                    "delete": True,
                    "import": True,
                    "export": True
                }
            },
            "columns": self._generate_columns_config(sql_auto)
        }

    def _generate_java_config(self, sql_auto: dict) -> dict:
        """生成Java配置

        Args:
            sql_auto: SQL解析结果

        Returns:
            dict: Java配置
        """
        config = {
            "table": {
                "package_name": "com.miaoma",
                "root_path": "artifacts/miaoma/generated/java"
            },
            "columns": {}
        }

        # 添加字段配置
        for column in sql_auto["columns"]:
            config["columns"][column["name"]] = {}

        return config

    def _generate_config(self, sql_auto: Dict[str, Any], fmt: str) -> Dict[str, Any]:
        """生成指定格式的配置

        Args:
            sql_auto: SQL解析结果
            fmt: 配置格式

        Returns:
            Dict[str, Any]: 生成的配置
        """
        if fmt == "common":
            return self._generate_common_config(sql_auto)
        elif fmt == "java":
            return self._generate_java_config(sql_auto)
        else:
            raise ValueError(f"不支持的配置格式: {fmt}")

    def _map_data_type(self, sql_type: str) -> str:
        """映射SQL类型到前端数据类型

        Args:
            sql_type: SQL类型

        Returns:
            str: 前端数据类型
        """
        sql_type = sql_type.upper()
        if sql_type in ["TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT", "FLOAT", "DOUBLE", "DECIMAL"]:
            return "number"
        elif sql_type in ["CHAR", "VARCHAR", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"]:
            return "text"
        elif sql_type in ["DATE", "TIME", "DATETIME", "TIMESTAMP"]:
            return "datetime"
        elif sql_type in ["TINYBLOB", "BLOB", "MEDIUMBLOB", "LONGBLOB"]:
            return "binary"
        elif sql_type == "BOOLEAN":
            return "boolean"
        else:
            return "text"

    def _get_format(self, sql_type: str) -> Optional[str]:
        """获取字段格式

        Args:
            sql_type: SQL类型

        Returns:
            Optional[str]: 字段格式
        """
        sql_type = sql_type.upper()
        if sql_type == "DATE":
            return "YYYY-MM-DD"
        elif sql_type == "TIME":
            return "HH:mm:ss"
        elif sql_type in ["DATETIME", "TIMESTAMP"]:
            return "YYYY-MM-DD HH:mm:ss"
        else:
            return None
